<?php


namespace models\Business;


use models\Exception\Business\AlibabaproductException;
use models\Exception\Business\AnnounceException;
use models\Exception\Business\MemberException;
use models\Exception\Business\OrderException;
use models\Exception\Business\TurnoverException;
use models\Exception\DAO\ModelDriverException;
use models\Exception\DAO\ModelException;
use models\Exception\DAO\ModelReflectionException;
use models\Exception\DAO\ModelSqlException;
use models\Exception\Service\ServiceException;
use models\Exception\Transformer\TransformerException;
use models\Service\AlibabaproductService;
use models\Service\AnnounceService;
use models\Service\MemberService;
use models\Service\TurnoverService;
use Yaf\Exception;
use Yaf\Registry;
use ylPush\Push;

class JPush
{
    const APP_KEY = '9fe08654a214ed2edc6aea82';
    const MASTER_KEY = 'f1f5885fa6f92d4ea453bff0';

    // 提现的推送消息正文
    const WITHDRAW_MSG = [
        'apply' => '您申请的提现%amount元已成功提交审核，请耐心等待。订单号：%sn',
        'success' => '您申请的提现%amount元已审核通过，请留意您的收款账户。订单号：%sn',
        'failure' => '您申请的提现%amount元因“%reason”的原因审核不通过，如有疑问请联系客服。'
    ];
    // 有关提现的，允许发送推送通知的action
    const WITHDRAW_ALLOWED_ACTION = ['apply', 'success', 'failure'];

    // 拼团相关推送消息正文
    const COUPON_MSG = [
        'failure' => '',
        'success' => '',
        'no_profit_4_winner' => '您参与的%title拼单交易失败，您所支付的金额已全额退回您的余额，请注意查收。订单号：%sn',
        'no_profit_4_loser' => '您参与的%title拼单交易失败，您所支付的金额已全额退回您的余额，请注意查收。订单号：%sn'
    ];

    /**
     * 根据registration_id与msg_id查询消息推送状态
     * @param $msg_id
     * @param $registration_id
     * @return bool
     * @throws AnnounceException
     */
    static public function getStatus($msg_id, $registration_id) {
        if (!is_integer($msg_id))
            throw new AnnounceException(AnnounceException::INVALID_MSG_ID, AnnounceException::INVALID_MSG_ID_NO);

        $header = [
            'Authorization: Basic ' . base64_encode(self::APP_KEY . ':' . self::MASTER_KEY),
            'Content-Type: application/json'
        ];

        $push = new Push();
        $push->setAppKey(self::APP_KEY);
        $push->setMasterSecret(self::MASTER_KEY);
        $push->setHeader($header);
        $push->params = [
            'msg_id' => $msg_id, // 这个参数必须是int
            'registration_ids' => [
                $registration_id
            ]
        ];

        $status_arr = $push->jpush_report->message();

        return isset($status_arr[$registration_id]) && $status_arr[$registration_id]['status'] == 0;
    }

    /**
     * 根据订单编号 给参与拼团的两个用户推送对应的消息
     * @param string $sn
     * @throws AnnounceException
     * @throws ModelDriverException
     * @throws ModelException
     * @throws ModelSqlException
     * @throws OrderException
     * @throws ServiceException
     */
    static public function couponResultPush($sn = '') {
        if (empty($sn))
            throw new OrderException(OrderException::ORDER_ID_IS_EMPTY, OrderException::ORDER_ID_IS_EMPTY_NO);

        try {
            $order_info = Order::getOrderBySn($sn);
            if (empty($order_info))
                throw new OrderException(OrderException::ORDER_IS_NOT_EXISTS, OrderException::ORDER_IS_NOT_EXISTS_NO);
        } catch (\Exception $e) {
            throw $e;
        }

        // 获取拼团会员信息
        try {
            $member_list = MemberService::getInstance()->getList(1, 2, 'desc', 'id',
                ['groupOp' => 'AND', 'rules' => [
                    ['field' => 'id', 'op' => 'in', 'data' => $order_info['member_id'] . ',' . $order_info['fail_member_id']]]]);
            if (empty($member_list['data']))
                throw new MemberException(MemberException::MEMBER_IS_NOT_EXISTS, MemberException::MEMBER_IS_NOT_EXISTS_NO);
        } catch (\Exception $e) {
            throw $e;
        }
        //获取商品标题
        $product =  AlibabaproductService::getInstance()->getOne($order_info['product_id']);
        if (empty($product))
            throw new AlibabaproductException(AlibabaproductException::ALIBABAPRODUCT_IS_NOT_EXISTS, AlibabaproductException::ALIBABAPRODUCT_IS_NOT_EXISTS_NO);
        $msg_arr = [];
        foreach ($member_list['data'] as $member_info) {
            if (!empty($member_info['registration_id']) && $member_info['id'] == $order_info['fail_member_id']) {
                $fail_msg='您在“'.$product['title'].'”拼单中未拼中商品，商品金额将会退还到您的余额，请注意查收。订单号：'.$sn;
                $msg_arr['lose'] = ['msg' => $fail_msg,
                    'registration_id' => $member_info['registration_id'], 'member_id' => $member_info['id']];
            }

            if (!empty($member_info['registration_id']) && $member_info['id'] == $order_info['member_id']) {
                $success_msg='您在“'.$product['title'].'”拼单中拼中商品，请等待卖家发货，请留意快递信息。订单号：'.$sn;
                $msg_arr['win'] = ['msg' => '恭喜你，拼单胜出，请等待卖家发货，请留意快递信息。',
                    'registration_id' => $member_info['registration_id'], 'member_id' => $member_info['id']];
            }
        }

        if (empty($msg_arr))
            throw new AnnounceException(AnnounceException::INVALID_PUSH_MSG, AnnounceException::INVALID_PUSH_MSG_NO);

        $push = new Push();

        $push->setAppKey(self::APP_KEY);
        $push->setMasterSecret(self::MASTER_KEY);

        $header = [
            'Authorization: Basic ' . base64_encode($push->app_key . ':' . $push->master_secret),
            'Content-Type: application/json'
        ];
        $push->setHeader($header);

        $announce_list = [];
        foreach ($msg_arr as $type => $msg) {
            // 推送
            $params = [
                'platform' => 'all',
                'audience' => [
                    'registration_id' => [$msg['registration_id']]
                ],
                'notification' => [
                    'alert' => $msg['msg']
                ],
                'message' => [
                    'msg_content' => 'content',
                    'title' => 'msg',
                    'content_type' => 'text',
                    'extras' => [
                        'type' => $type === 'win' ? 5 : 10, // 类型 1为跳转首页,2为跳转产品详情页,3为系统消息列表页,4为系统消息详情页,5为订单详情页,6为余额页面
                        'id' => $type === 'win' ? $order_info['sn'] : 0, // 当type为2时表示产品编号，当type为4时表示系统消息编号,当type为5时表示订单编号
                    ]
                ]
            ];

            $push->params = $params;
            // 按registration_id推送消息
            $res = $push->jpush->pushPost();

            array_push($announce_list, [
                'member_id' => $msg['member_id'],
                'type' => 1,
                'title' => $msg['msg'],
                'content' => $msg['msg'],
                'stats' => 1,
                'is_push' => 1,
                'msg_id' => isset($res['sendno']) ? $res['msg_id'] : 0
            ]);

            Registry::get('push_log')->info('推送结果: ' . json_encode($res));
        }

        if (!empty($announce_list))
            AnnounceService::getInstance()->batchInsert($announce_list);
    }

    /**
     * 根据订单编号 查询对应订单状态 并给订单所属会员推送消息
     * @param string $sn
     * @return mixed
     * @throws AnnounceException
     * @throws ModelDriverException
     * @throws ModelException
     * @throws ModelReflectionException
     * @throws ModelSqlException
     * @throws OrderException
     * @throws ServiceException
     * @throws TransformerException
     * @throws \Yaf\Exception
     */
    static public function orderPush($sn = '') {
        if (empty($sn))
            throw new OrderException(OrderException::ORDER_ID_IS_EMPTY, OrderException::ORDER_ID_IS_EMPTY_NO);

        $order_info = \models\Business\Order::getOrderBySn($sn);
        if (empty($order_info))
            throw new \Yaf\Exception("订单不存在");

        $msg = '';
        $wait_for_buyer_send = $wait_for_seller_receive = $apply_support = $return_success = false;
        if ($order_info['refund_stats'] == 3) {
            $msg = '订单(编号:' . $sn . ')退款成功。相关款项已退至您的余额，请注意查收。';
        } else if ($order_info['refund_stats'] == 4) {
            $msg = '订单(编号:' . $sn . ')退货成功。相关款项已退至您的余额，请注意查收。';
            $return_success = true;
        } else if ($order_info['refund_stats'] == 7) {
            $msg = '订单(编号:' . $sn . ')卖家已同意退货，请联系快递退货，并到订单详情页面填写退货快递单号。';
            $wait_for_buyer_send = true;
        } else if ($order_info['refund_stats'] == 8) {
            $msg = '订单(编号:' . $sn . ')已退货，商品正在快递回卖家地址的过程中。请耐心等待卖家收货。';
            $wait_for_buyer_send = true;
        } else if ($order_info['refund_stats'] == 5) {
            $msg = '订单(编号:' . $sn . ')退款失败，卖家拒绝退款。若您坚持退款，请联系客服。';
            $apply_support = true;
        } else if ($order_info['refund_stats'] == 6) {
            $msg = '订单(编号:' . $sn . ')退货失败，卖家拒绝退货。若您坚持退货，请联系客服';
            $apply_support = true;
        }

        if (empty($msg))
            throw new AnnounceException(AnnounceException::INVALID_PUSH_MSG, AnnounceException::INVALID_PUSH_MSG_NO);

        try {
            $member_info = \models\Business\Member::getMemberInfoById($order_info['member_id']);
            if (empty($member_info))
                throw new MemberException(MemberException::MEMBER_IS_NOT_EXISTS, MemberException::MEMBER_IS_NOT_EXISTS_NO);
        } catch (\Exception $e) {
            throw $e;
        }

        $push = new Push();

        $push->setAppKey(self::APP_KEY);
        $push->setMasterSecret(self::MASTER_KEY);

        $header = [
            'Authorization: Basic ' . base64_encode($push->app_key . ':' . $push->master_secret),
            'Content-Type: application/json'
        ];
        $push->setHeader($header);

        // 推送
        $params = [
            'platform' => 'all',
            'audience' => [
                'registration_id' => [$member_info['registration_id']]
            ],
            'notification' => [
                'alert' => $msg
            ],
            'message' => [
                'msg_content' => 'content',
                'title' => 'msg',
                'content_type' => 'text',
            ]
        ];
        if ($wait_for_buyer_send === true) {
            $params['message']['extras'] = [
                'type' => 5, // 跳转到进行中、待付款、未拼中的订单详情页
                'id' => $order_info['sn'], // 当type为2时表示产品编号，当type为4时表示系统消息编号,当type为5时表示订单编号
            ];
        }
        if ($return_success === true) {
            $params['message']['extras'] = [
                'type' => 6, // 跳转到其他拼单订单详情页
                'id' => $order_info['sn']
            ];
        }
        // 提示买家联系客服
        if ($apply_support === true) {
//            $params['message']['extras'] = [
//                'type' => 5, // 类型 1为跳转首页,2为跳转产品详情页,3为系统消息列表页,4为系统消息详情页,5为订单详情页,6为余额页面
//                'id' => $order_info['sn'], // 当type为2时表示产品编号，当type为4时表示系统消息编号,当type为5时表示订单编号
//            ];
        }

        $push->params = $params;
        // 按registration_id推送消息
        $res = $push->jpush->pushPost();

        $current_date = date('Y-m-d H:i:s');
        // $type = 0, $member_id = 0, $title = "", $content = "", $stats = 0, $is_push = 0,
        // $msg_id = ""
        AnnounceService::getInstance()->create(1, $member_info['id'], $msg, $msg, 1, 1,
            $res['sendno'] ? $res['msg_id'] : 0, $current_date, 0, $current_date, 9);

        Registry::get('push_log')->info('推送结果: ' . json_encode($res));

        return $res;
    }

    static public function push($registration_id, $title, $content) {
        $push = new Push();

        $push->setAppKey(self::APP_KEY);
        $push->setMasterSecret(self::MASTER_KEY);

        $header = [
            'Authorization: Basic ' . base64_encode($push->app_key . ':' . $push->master_secret),
            'Content-Type: application/json'
        ];
        $push->setHeader($header);

        // 推送
        $params = [
            'platform' => 'all',
            'audience' => [
                'registration_id' => [$registration_id]
            ],
            'notification' => [
                'alert' => $content
            ],
            'message' => [
                'msg_content' => 'content',
                'title' => 'msg',
                'content_type' => 'text',
                'extras' => [
                    'type' => 3, // 类型 1为跳转首页,2为跳转产品详情页,3为系统消息列表页,4为系统消息详情页,5为订单详情页,6为余额页面
                    'id' => 4, // 当type为2时表示产品编号，当type为4时表示系统消息编号,当type为5时表示订单编号
                ]
            ]
        ];


        $push->params = $params;
        // 按registration_id推送消息
        $res = $push->jpush->pushPost();

        Registry::get('push_log')->info('推送结果: ' . json_encode($res));

        return $res;
    }

    /**
     * 提现消息推送
     * @param string $action
     * @param string $sn
     * @return mixed
     * @throws AnnounceException
     * @throws ModelDriverException
     * @throws ModelException
     * @throws ModelSqlException
     * @throws OrderException
     * @throws ServiceException
     * @throws TurnoverException
     */
    static public function withdrawPush($sn = '', $action = 'apply') {
        if (empty($sn))
            throw new OrderException(OrderException::ORDER_ID_IS_EMPTY, OrderException::ORDER_ID_IS_EMPTY_NO);
        if (!in_array($action, self::WITHDRAW_ALLOWED_ACTION))
            throw new TurnoverException("非法操作", 403);

        if ($action !== 'apply') {
            try {
                $order_info = Finance::getWithdrawOrders(['sn' => $sn]);
                $order_info = $order_info['data'][0];
                if (empty($order_info))
                    throw new TurnoverException(TurnoverException::TURNOVER_IS_NOT_EXISTS, TurnoverException::TURNOVER_IS_NOT_EXISTS_NO);
            } catch (\Exception $e) {
                throw $e;
            }
        } else {
            try {
                $order_info = TurnoverService::getInstance()->getOne($sn);
                if (empty($order_info))
                    throw new TurnoverException(TurnoverException::TURNOVER_IS_NOT_EXISTS, TurnoverException::TURNOVER_IS_NOT_EXISTS_NO);
            } catch (\Exception $e) {
                throw $e;
            }
        }

        // 获取拼团会员信息
        try {
            $member_info = MemberService::getInstance()->getOne($order_info['member_id']);
            if (empty($member_info))
                throw new MemberException(MemberException::MEMBER_IS_NOT_EXISTS, MemberException::MEMBER_IS_NOT_EXISTS_NO);
        } catch (\Exception $e) {
            throw $e;
        }

        if (!isset(self::WITHDRAW_MSG[$action]))
            throw new AnnounceException(AnnounceException::ANNOUNCE_IS_NOT_EXISTS, AnnounceException::ANNOUNCE_IS_NOT_EXISTS_NO);
        else {
            $msg = [
                'msg' => str_replace(
                    ['%sn', '%amount', '%reason'],
                    [$order_info['sn'], $order_info['amount'], ($action == 'failure' && empty($order_info['remark']) ? '管理员拒绝' : $order_info['remark'])],
                    self::WITHDRAW_MSG[$action]
                ),
                'registration_id' => $member_info['registration_id'], 'member_id' => $member_info['id']];
        }
        if (! $msg)
            throw new AnnounceException(AnnounceException::INVALID_PUSH_MSG, AnnounceException::INVALID_PUSH_MSG_NO);

        $push = new Push();

        $push->setAppKey(self::APP_KEY);
        $push->setMasterSecret(self::MASTER_KEY);

        $header = [
            'Authorization: Basic ' . base64_encode($push->app_key . ':' . $push->master_secret),
            'Content-Type: application/json'
        ];
        $push->setHeader($header);

        $announce_list = [];
        // 推送
        $params = [
            'platform' => 'all',
            'audience' => [
                'registration_id' => [$msg['registration_id']]
            ],
            'notification' => [
                'alert' => $msg['msg']
            ],
            'message' => [
                'msg_content' => 'content',
                'title' => 'msg',
                'content_type' => 'text',
                'extras' => [
                    'type' => 10, // 类型 1为跳转首页,2为跳转产品详情页,3为系统消息列表页,4为系统消息详情页,5为订单详情页,6为余额页面
//                    'id' => 4, // 当type为2时表示产品编号，当type为4时表示系统消息编号,当type为5时表示订单编号
                ]
            ]
        ];

        $push->params = $params;
        // 按registration_id推送消息
        $res = $push->jpush->pushPost();

        array_push($announce_list, [
            'member_id' => $msg['member_id'],
            'type' => 1,
            'title' => $msg['msg'],
            'content' => $msg['msg'],
            'stats' => 1,
            'is_push' => 1,
            'msg_id' => isset($res['sendno']) ? $res['msg_id'] : 0
        ]);

        Registry::get('push_log')->info('推送结果: ' . json_encode($res));

        if (!empty($announce_list))
            AnnounceService::getInstance()->batchInsert($announce_list);

        return $res;
    }
}
